import java.util.ArrayList;


public class Stat2 {

	private class RangeTuple {
		double low;
		double high;
		int count;
		
		public RangeTuple(double low, double high, int count) {
			this.low = low;
			this.high = high;
			this.count = count;
		}
	}
	
	double W_1;
	double W_2;
	
	ArrayList<RangeTuple> range_1 = new ArrayList<RangeTuple>();
	ArrayList<RangeTuple> range_2 = new ArrayList<RangeTuple>();
	
	Stat1 stat1;
	private boolean verbose;
	
	public Stat2(ArrayList<Tuple> r, int b1, int b2, boolean verbose) {
		this.verbose = verbose;
		report("\nSet 2 stats:");
		stat1 = new Stat1(r, false);
		
		// bucketize A1 with b1 buckets
		double W = Math.floor( (stat1.high_a1 - stat1.low_a1) / b1 );
		W_1 = W;
		double m = stat1.low_a1;
		double M = stat1.high_a1;
		
		// form b1 buckets
		for (int i = 0; i < b1 ; i++) {
			// m + (i-1)*W,   m + i*w
			// count the number of things between this range in the tuple
			double chunkLow = m + i * W;
			double chunkHigh = m + (i+1) * W;
			
			int count = 0;
			for (Tuple t : r) {
				if (chunkLow <= t.A1 && t.A1 <= chunkHigh)  {
					count++;
				}
			}
			report("A1 [" + chunkLow + ", " + chunkHigh + "):" + count);
			range_1.add(new RangeTuple(chunkLow, chunkHigh, count));
		}
		
		
		// bucktize A2 with b2 buckets
		W = Math.floor( (stat1.high_a2 - stat1.low_a2) / b2 );
		W_2 = W;
		m = stat1.low_a2;
		M = stat1.high_a2;
		
		for (int i = 0; i < b2 ; i++) {
			// m + i,   m + i*w
			// count the number of things between this range in the tuple
			double chunkLow = m + i * W;
			double chunkHigh = m + (i+1) * W;
			
			int count = 0;
			for (Tuple t : r) {
				if (chunkLow <= t.A2 && t.A2 <= chunkHigh)  {
					count++;
				}
			}
			report("A2 [" + chunkLow + ", " + chunkHigh + "):" + count);
			range_2.add(new RangeTuple(chunkLow, chunkHigh, count));
		}
		
	}

	private void report(String string) {
		if (verbose) System.out.println(string);
		
	}

	public double[] getWidth(ArrayList<Tuple> r, int b1, int b2) {
		return new double[] {W_1, W_2};
	}

	public double getEstimatedCount(int r1, int s1, String string) {
		// counts the heights of histogram sections that fall between r1 and s1
		int estimatedCount = 0;
		ArrayList<RangeTuple> range;
		if (string.equals("A1")) 
			range = range_1;
		else range = range_2;

		// for each tuple
		for (RangeTuple t : range) {
			
			if (t.high < r1 || t.low > s1) continue;
			
			// if the tuple falls totally within the window, add its height
			if (r1 <= t.low && t.high < s1) {
				estimatedCount += t.count;
			}
			else {
				// if it dips low
				if (t.low < r1)
					estimatedCount += t.count * (t.high - r1)/(t.high - t.low);
				// if it dips high
				if (t.high > s1)
					estimatedCount += t.count * (s1 - t.low)/(t.high - t.low);
			}
		}
		report("   Set2 estimates " + string + " has " + estimatedCount + " tuples between " + r1 + " and " + s1);
		
		return estimatedCount;
	}
}
